using System;
using System.Collections.Generic;
using Cfg.Builders;
using Cfg.ConfigProviders;
using Cfg.Exceptions;
using Cfg.Proxies;

namespace Cfg
{
    /// <summary>
    /// 
    /// </summary>
    public static class AppSettings
	{
        public static readonly ConfiguratorSettings Settings = new ConfiguratorSettings();

        public static Dictionary<Type, object> Container = new Dictionary<Type, object>(); 

        public static T Get<T>()
        {
            if (!Container.ContainsKey(typeof (T)))
            {
                Init<T>();
            }

            return (T)Container[typeof(T)];
        }

        /// <summary>
        /// Initializes configuration.
        /// Validates and sets configuration values.
        /// </summary>
        /// <typeparam name="T">Configuration type</typeparam>
        /// <param name="context">In which context configuration is used.</param>
        /// <exception cref="ConfigValidationException"></exception>
        public static void Init<T>(string context = null)
        {
            Init<T>(Settings.DefaultConfigFileProvider, context);
        }

        /// <summary>
        /// 
        /// </summary>
        /// <typeparam name="T"></typeparam>
        /// <param name="configFileProvider"></param>
        /// <param name="context"></param>
        public static void Init<T>(IConfigFileProvider configFileProvider, string context = null)
        {
            var type = typeof(T);

            // set type initialized
            Container[type] = null;
            object instance = null;

            if (type.IsInterface)
            {
                var proxy = ProxyBuilder.CreateProxy<T>();
                instance = Container[type] = proxy;
                type = proxy.GetType();
            }

            var configBuilder = new ConfigBuilder(type, instance, configFileProvider, context);

            var errors = configBuilder.GetErrors();

            if (errors.Length > 0)
            {
                throw new ConfigValidationException<T>(errors);
            }
        }

        /*
        /// <summary>
        /// Initialize configs. Configurations must be in calling assebly
        /// </summary>
        /// <param name="context"></param>
        [Obsolete]
		public static void Init(string context = null)
		{
			var configs = Assembly.GetCallingAssembly()
				.GetTypes()
				.Where(x => x.GetCustomAttributes(typeof(ConfigAttribute), false).Any());

            var errors = new Dictionary<Type, ValidationError[]>();
			foreach (var type in configs)
			{
			    var config = new Configuration(type, context);
			    var typeErrors = config.SetValues();
                if (typeErrors.Length > 0)
                {
                    errors[type] = typeErrors;
                }
			}

            if (errors.Count > 0)
            {
                var message = new StringBuilder();

                foreach (var typeErrors in errors)
                {
                    message
                        .AppendFormat("Invalid values in configuration '{0}':", typeErrors.Key)
                        .AppendLine();

                    foreach (var error in typeErrors.Value)
                    {
                        message
                            .AppendFormat("{0}: {1}", error.Key, error.Error)
                            .AppendLine();
                    }
                }

                throw new Exception(message.ToString());
            }
		}
         */
	}
}